package com.thm.tfast.core.oss;

import io.minio.*;
import io.minio.http.Method;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * @author THM
 * @date 2022/10/27
 * @desc minio对象存储服务
 */
@Slf4j
@Component
public class MinioOssService extends AbstractOssService {
    @Resource
    private MinioClient minioClient;
    /**
     * 查看存储bucket是否存在
     * @return boolean
     */
    public Boolean bucketExists(String bucketName) {
        try {
            return minioClient.bucketExists(BucketExistsArgs
                    .builder()
                    .bucket(bucketName)
                    .build());
        } catch (Exception e) {
            log.error("查看桶异常，bucketName={}，e={}",bucketName,e.getMessage());
            return false;
        }
    }

    /**
     * 查看存储bucket是否存在 不存在则创建
     * @return boolean
     */
    public Boolean bucketExistsAndCreate(String bucketName) {
        if (!bucketExists(bucketName)) return makeBucket(bucketName);
        return false;
    }

    /**
     * 创建存储bucket
     * @return Boolean
     */
    public Boolean makeBucket(String bucketName) {
        try {
            minioClient.makeBucket(MakeBucketArgs.builder()
                    .bucket(bucketName)
                    .build());
        } catch (Exception e) {
            log.error("创建桶异常，bucketName={}，e={}",bucketName, e.getMessage());
            return false;
        }
        return true;
    }

    /**
     * 删除存储bucket
     * @return Boolean
     */
    public Boolean removeBucket(String bucketName) {
        try {
            minioClient.removeBucket(RemoveBucketArgs.builder()
                    .bucket(bucketName)
                    .build());
        } catch (Exception e) {
            log.error("删除桶异常，bucketName={}，e={}",bucketName,e.getMessage());
            return false;
        }
        return true;
    }

    @Override
    public String upload(String bucketName, String fileName, MultipartFile file) {
        bucketExistsAndCreate(bucketName);
        try (InputStream inputStream = file.getInputStream()){
            PutObjectArgs objectArgs = PutObjectArgs
                    .builder()
                    .bucket(bucketName)
                    .object(fileName)
                    .stream(inputStream, inputStream.available(),-1)
                    .contentType(file.getContentType())
                    .build();
            //文件名称相同会覆盖
            minioClient.putObject(objectArgs);
        } catch (Exception e) {
            log.error("上传文件异常，bucketName={}，fileName={}, e={}",bucketName,fileName, e.getMessage());
        }
        return getUrl(bucketName,fileName);
    }

    @Override
    public Map<String, String> uploadBatch(String bucketName, Map<String, MultipartFile> files) {
        Map<String, String> map = new HashMap<>();
        for (Map.Entry<String, MultipartFile> entry : files.entrySet()) {
            String url = upload(bucketName, entry.getKey(), entry.getValue());
            map.put(entry.getKey(), url);
        }
        return map;
    }

    @Override
    public InputStream download(String bucketName, String fileName) {
        InputStream inputStream = null;
        try {
            GetObjectArgs objectArgs = GetObjectArgs
                    .builder()
                    .bucket(bucketName)
                    .object(fileName)
                    .build();
            inputStream = minioClient.getObject(objectArgs);
        } catch (Exception e){
            log.error("下载文件异常，bucketName={}，fileName={}, e={}",bucketName,fileName, e.getMessage());
        }
        return inputStream;
    }

    @Override
    public void download(String bucketName, String fileName, HttpServletResponse response) {
        try (ServletOutputStream outputStream = response.getOutputStream()){
            outputStream.write(downloadToByte(bucketName,fileName));
            outputStream.flush();
        } catch (Exception e){
            log.error("下载文件异常，bucketName={}，fileName={}, e={}",bucketName,fileName, e.getMessage());
        }
    }

    @Override
    public byte[] downloadToByte(String bucketName, String fileName) {
        try (ByteArrayOutputStream os = new ByteArrayOutputStream();
             InputStream inputStream = download(bucketName,fileName)){
            byte[] buffer = new byte[1024];
            int n;
            while (-1 != (n = inputStream.read(buffer))) {
                os.write(buffer, 0, n);
            }
            return os.toByteArray();
        } catch (Exception e){
            log.error("下载文件异常，bucketName={}，fileName={}, e={}",bucketName,fileName, e.getMessage());
        }
        return null;
    }

    @Override
    public Boolean remove(String bucketName, String fileName) {
        try {
            minioClient.removeObject(RemoveObjectArgs
                    .builder()
                    .bucket(bucketName)
                    .object(fileName)
                    .build());
        }catch (Exception e){
            log.error("删除文件异常，bucketName={}，fileName={}, e={}",bucketName,fileName, e.getMessage());
            return false;
        }
        return true;
    }

    @Override
    public Boolean removeBatch(String bucketName, List<String> fileNames) {
        AtomicBoolean flag = new AtomicBoolean(true);
        fileNames.forEach(fileName -> {
            Boolean remove = remove(bucketName, fileName);
            if (!remove){
                flag.set(false);
            }
        });
        return flag.get();
    }

    @Override
    public String getUrl(String bucketName, String fileName) {
        try {
            // 查看文件地址
            GetPresignedObjectUrlArgs build = new GetPresignedObjectUrlArgs().builder().bucket(bucketName).object(fileName).method(Method.GET).build();
            String fileUrl = minioClient.getPresignedObjectUrl(build);
            return fileUrl.substring(0, fileUrl.indexOf("?"));
        } catch (Exception e) {
            log.error("获取文件访问地址异常，bucketName={}，fileName={}, e={}",bucketName,fileName, e.getMessage());
        }
        return null;
    }
}
